home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-06-20 | 10.9 KB | 349 lines | [TEXT/MPS ] |
- /* @(#) SavvyInit.c 6/19/92
- {Sources}Hack:SavvyInit.c
-
- No rights reserved
-
- Product: Joel’s MacHack ’92 entry
- File: SavvyInit.c
- Author: Joel West, Palomar Software
- Date: Wed, Jun 17, 1992
- Description: Code for “Savvy” Extension (INIT)
-
-
- TO DO:
- Invalidate Finder cache so we are displayed every time
- Handle updates (so icon is displayed after window is covered)
- Crimp clipregion to icon size
- test on non color QD
-
- Entry category (with apologies to the Emmies):
- Serious, Apple Marketing Politically Correct, first hack written
- by a manager while at MacHack that include source.
-
- Sources:
- IsSavvyTool.c stand-alone testbench (not otherwised used)
- IconSuite.h System 7 icon utilities from TN #306
- Savvy.a glue for trap patches
- Savvy.h header for C, Rez
- Savvy.make Makefile for everything
- SavvyInit.c code for the INIT and trap patches
- SavvyInit.r resources for the INIT
- ShowINIT.a standard developer CD
- Usage:
- BuildProgram Savvy
- */
-
- #undef qCheckHeapUsage
-
- #include <Traps.h>
- #include <GestaltEqu.h>
- #include <Events.h>
- #include <OSUtils.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <Errors.h>
- #include <string.h>
- #include "Savvy.h"
-
- #ifdef qUseIconSuite
- # include "IconSuite.h"
- #endif qUseIconSuite
-
- #define PRIVATE static
- PRIVATE Handle GetDetachRsrc(OSType thetype,Integer theid);
- PRIVATE void PlotSavviness(TGlobalsPtr gptr);
- PRIVATE void DimRect(Integer top,Integer left, Integer bottom,Integer right);
- #ifdef qUseIconSuite
- PRIVATE OSErr PopulateIconSuite(Integer resid,Handle *psuiteh);
- #endif qUseIconSuite
-
- /*
- Biggest problem:
- The biggest problem is that the Finder caches the information so
- we are not displayed on the second “Get Info” for the same
- application, UNLESS you close the folder window in between
- Get Info to flush the cache. The work-around should probably
- be to implement a comparable cache here. Or better yet,
- just touch the mod date of the parent folder, which
- invalidates the cache.
- Another biggie:
- The general approach for fooling the Finder is suitable only for a
- one-time tool (but then it is a 2-day hack, not a product…)
- */
- /* Install the trap patches to make this all work, UNLESS:
- 1) Not System 7; or
- 2) Holding down Command key
- Note: we need to make sure the info we need is properly loaded and
- stashed in the system heap, so it will be available later.
- */
- void InitEntry(void)
- { long attribute=0;
-
- #ifdef qCheckHeapUsage
- DebugStr("\p;HX @SysZone;HT;G");
- #endif qCheckHeapUsage
- /* Check for Apple Events present, since those are the most interesting we check for */
- if (Gestalt(gestaltAppleEventsAttr,&attribute) == noErr &&
- attribute & (1<<gestaltAppleEventsPresent)) {
- KeyMap thekeys;
-
- GetKeys(thekeys);
- if (!(thekeys[1] & 0x008000)) {
- TGlobalsPtr gptr;
- ShowINIT(kICNN_DoSavvy,kShowInitStdOffset);
-
- (void) GetDetachRsrc('INIT',0);
- gptr = GetGlobals();
- gptr->lastSizeValid = false;
-
- /* Detach the resources we will need later */
- gptr->hFinderNameString = GetDetachRsrc('STR ',kSTR_Finder);
- gptr->hGetInfoSubstrString = GetDetachRsrc('STR ',kSTR_GetInfoSubstr);
-
- /* Load the icons that will be used for displaying */
- #ifdef qUseIconSuite
- { Boolean iconloadfailed=false;
- THz currzone = GetZone();
-
- SetZone(SystemZone());
- /* We might want to skip this to save RAM on a non-color QD machine */
- if (PopulateIconSuite(kICNN_24bitclean,&gptr->h24bitIconSuite) ||
- PopulateIconSuite(kICNN_32bitclean,&gptr->h32bitIconSuite) ||
- PopulateIconSuite(kICNN_NotAtAllSavvy,&gptr->hUnsavvyIconSuite))
- iconloadfailed = true;
- SetZone(currzone);
- if (iconloadfailed)
- goto error_return;
- }
- #else qUseIconSuite
- gptr->h24bitIcon = GetDetachRsrc('ICN#',kICNN_24bitclean);
- gptr->h32bitIcon = GetDetachRsrc('ICN#',kICNN_32bitclean);
- gptr->hUnsavvyIcon = GetDetachRsrc('ICN#',kICNN_NotAtAllSavvy);
-
- if (!gptr->h24bitIcon || !gptr->h32bitIcon || !gptr->hUnsavvyIcon)
- goto error_return;
- #endif qUseIconSuite
- /* Now that everything else went OK, install trap patches */
- gptr->oldGet1Resource =
- (GetResourceProcPtr) NGetTrapAddress(_Get1Resource,ToolTrap);
- NSetTrapAddress((long) Get1ResourceWrapper,_Get1Resource,ToolTrap);
-
- gptr->oldNewCWindow =
- (NewWindowProcPtr) NGetTrapAddress(_NewCWindow,ToolTrap);
- NSetTrapAddress((long) NewCWindowTailPatch,_NewCWindow,ToolTrap);
-
- gptr->oldNewWindow =
- (NewWindowProcPtr) NGetTrapAddress(_NewWindow,ToolTrap);
- NSetTrapAddress((long) NewWindowTailPatch,_NewWindow,ToolTrap);
-
- gptr->oldShowWindow =
- (ShowWindowProcPtr) NGetTrapAddress(_ShowWindow,ToolTrap);
- NSetTrapAddress((long) ShowWindowTailPatch,_ShowWindow,ToolTrap);
-
- #ifdef qCheckHeapUsage
- DebugStr("\p;HT");
- /* NOTE: You should also add in the size of the 'INIT' resource */
- #endif qCheckHeapUsage
- return;
- }
- }
- error_return:
- ShowINIT(kICNN_Unsavvy,kShowInitStdOffset);
- }
-
- /* Get a resource at boot time that we want to keep after INIT closes */
- PRIVATE Handle GetDetachRsrc(OSType thetype,Integer theid)
- { Handle h=Get1Resource(thetype,theid);
-
- if (h) {
- HNoPurge(h);
- DetachResource(h);
- }
- return h;
- }
- #ifdef qUseIconSuite
- /* This uses the TN #306 mechanism to archive the known icons of this id
- Note, the utils can promote up from a B&W icon to color screen,
- but not demote down from color */
- PRIVATE OSErr PopulateIconSuite(Integer resid,Handle *psuiteh)
- { OSErr err;
- OSType icontype[3]={'ICN#','icl8','icl4'};
- Handle iconh;
- Integer i;
-
- *psuiteh = NULL;
- err = NewIconSuite(psuiteh);
- for (i=0; err==noErr && i<3; i++) {
- iconh = GetDetachRsrc(icontype[i],resid);
- if (iconh) {
- Handle newh=NULL;
- err = AddIconToSuite(iconh, *psuiteh, icontype[i]);
- } else
- if (i==0) // must get ICN# or else
- return resNotFound;
- }
- return err;
- }
- #endif qUseIconSuite
-
-
- pascal void Get1ResourceFilter(OSType thetype,Integer theid)
- {
- if (thetype=='SIZE') {
- Handle h;
- TGlobalsPtr gptr = GetGlobals();
- GetResourceProcPtr realtrap = gptr->oldGet1Resource;
-
- // Perhaps should tail patch instead, but…
- h = (*realtrap)(thetype,theid); // so steal our own copy
- if (h) {
- BlockMove(*h,&gptr->lastSizeRsrc,sizeof(TSizeStruct));
- gptr->lastSizeValid = true;
- gptr->possibleGetInfoWindow = false;
- }
- }
- }
-
- /* Heuristic:
- Expect a certain set of conditions in order to set a couple of flags
- If, at any point, things don’t look kosher, clear flags and turn
- off “in suspected Get Info” mode
- Yeah, we could patch MenuSelect in the Finder, etc., but…
-
- In deciding when/how to display the required information,
- this is CERTAINLY not what I would consider a shippable
- implementation. But then, app-specific patches (rather than global
- system patches) rarely are — since the interface to the system
- and/or ROM are documented, while the interface within any application
- is usually implementation-specific. See Leonard Rosenthol’s Finder
- QuickTime icon hack for another idea on how to do this displaying.
- */
- /* We should put our strings in a resource, obviously */
- Boolean AreWeInFinder(TGlobalsPtr gptr)
- { register Str31 *pcurname=gCurApName;
- StringHandle h=gptr->hFinderNameString; // English is "Finder"
- Integer len=Length(*h);
-
- if ((Length(pcurname) == len) &&
- memcmp(pcurname,*h,len+1)==0)
- return true;
- return false;
- }
-
- /* Common logic for NewWindowTailPatch(), NewCWindowTailPatch() */
- PRIVATE void DoWindowHeuristics(TGlobalsPtr gptr,Boolean visible)
- {
- if (!gptr->lastSizeValid)
- return; // don’t care without a 'SIZE'
-
- if (!gptr->possibleGetInfoWindow && !visible &&
- AreWeInFinder(gptr))
- gptr->possibleGetInfoWindow = true;
- else
- gptr->lastSizeValid = false; // misorder, clear flag
- }
-
- /* Perhaps these should be filters, but this was a later re-design */
- pascal WindowPtr NewWindowTailPatch(void *wStorage,const Rect *boundsRect,ConstStr255Param title,
- Boolean visible,short procID,WindowPtr behind,Boolean goAwayFlag,long refCon)
- { TGlobalsPtr gptr = GetGlobals();
- NewWindowProcPtr realtrap=gptr->oldNewWindow; // don’t trust compiler
- WindowPtr wp;
-
- wp = (*realtrap)(wStorage,boundsRect,title,visible,procID,behind,goAwayFlag,refCon);
- DoWindowHeuristics(gptr,visible);
- return wp;
- }
-
- pascal WindowPtr NewCWindowTailPatch(void *wStorage,const Rect *boundsRect,ConstStr255Param title,
- Boolean visible,short procID,WindowPtr behind,Boolean goAwayFlag,long refCon)
- { TGlobalsPtr gptr = GetGlobals();
- NewWindowProcPtr realtrap=gptr->oldNewCWindow; // don’t trust compiler
- WindowPtr wp;
-
- wp = (*realtrap)(wStorage,boundsRect,title,visible,procID,behind,goAwayFlag,refCon);
- DoWindowHeuristics(gptr,visible);
- return wp;
- }
-
- pascal void ShowWindowTailPatch(WindowPtr theWindow)
- { TGlobalsPtr gptr = GetGlobals();
- ShowWindowProcPtr realtrap=gptr->oldShowWindow;
-
- (*realtrap)(theWindow);
- if (gptr->lastSizeValid && gptr->possibleGetInfoWindow && AreWeInFinder(gptr)) {
- Str255 title;
- Integer len;
- StringHandle h=gptr->hGetInfoSubstrString; // English is " Info"
- Integer substrlen=Length(*h);
-
- GetWTitle(theWindow,title);
- len = Length(title);
- if (memcmp(&title[len-substrlen+1],&(*h)[1],substrlen)
- == 0)
- PlotSavviness(gptr);
- }
- gptr->lastSizeValid = false; // don’t check ever again
- }
-
- /* This is the routine that actually displays the savvy-ness indication icon */
- PRIVATE void PlotSavviness(TGlobalsPtr gptr)
- { Rect iconrect;
- Integer top=7,left=203,bottom=39,right=235;
- Boolean somewhatsavvy = (gptr->lastSizeRsrc.is32BitCompatible ||
- gptr->lastSizeRsrc.isHighLevelEventAware ||
- gptr->lastSizeRsrc.localAndRemoteHLEvents ||
- gptr->lastSizeRsrc.isStationeryAware ||
- gptr->lastSizeRsrc.useTextEditServices);
-
- /* We could display unsavvy icon using ttDisabled (TN #306, p.2)—but we don’t */
- SetRect(&iconrect, left, top, right, bottom);
- #ifdef qUseIconSuite
- (void) PlotIconSuite(&iconrect, atNone, ttNone,
- !somewhatsavvy ? gptr->hUnsavvyIconSuite :
- (gptr->lastSizeRsrc.is32BitCompatible ?
- gptr->h32bitIconSuite : gptr->h24bitIconSuite));
- #else qUseIconSuite
- PlotIcon(&iconrect,
- !somewhatsavvy ? gptr->hUnsavvyIcon :
- (gptr->lastSizeRsrc.is32BitCompatible ?
- gptr->h32bitIcon : gptr->h24bitIcon));
- #endif qUseIconSuite
-
- if (somewhatsavvy) { //don’t blast unsavvy icon
- if (!gptr->lastSizeRsrc.isHighLevelEventAware)
- DimRect(top,left,top+5,left+3);
- if (!gptr->lastSizeRsrc.localAndRemoteHLEvents)
- DimRect(top,right-3,top+5,right); // local only
- if (!gptr->lastSizeRsrc.isStationeryAware)
- DimRect(bottom-5,left,bottom,left+3);
- if (!gptr->lastSizeRsrc.useTextEditServices)
- DimRect(bottom-5,right-3,bottom,right);
- }
- }
-
- #define kHackGray 0xAA55AA55
- /* To do: support Color QD GrafPort */
- PRIVATE void DimRect(Integer top,Integer left, Integer bottom,Integer right)
- {
- #ifdef qUnused
- Pattern myGray;
- PenState savedPnState;
- #endif qUnused
- Rect r;
-
- SetRect(&r,left,top,right,bottom);
- #ifndef qUnused
- EraseRect(&r);
- #else qUnused
- GetPenState(&savedPnState);
- PenMode(patBic);
- ((long *) myGray)[0] = kHackGray;
- ((long *) myGray)[1] = kHackGray;
- PenPat(myGray);
- PaintRect(&r);
- SetPenState(&savedPnState);
- #endif qUnused
- }
-